﻿using UnityEngine;
using System.Collections;
using System.IO;
using System;
using System.Threading;

public class ScreenShotShare
{
	/// <summary>
    /// 截图开始之前，我们可以设置截图区域 
    /// </summary>
	public static Action onShotBeginCallBack;
	/// <summary>
    ///截图结束之后，我们进行分享等操作 
    /// </summary>
	public static Action onShotFinishedCallBack;
	private static string Title;
	private static string Content;
	private static string Url = string.Empty;
	private static string Name = string.Empty;
	private static Rect screen;
	
	// Use this for initialization
	static ScreenShotShare ()
	{		
		screen = new Rect(0, 0, Screen.width, Screen.height);
	}

	private static void SaveTexture(Texture2D tex2D, string path)
    {
        try
        {
            byte[] bytes = tex2D.EncodeToJPG(90);
            string fullPath = path;
            File.WriteAllBytes(fullPath, bytes);
            GC.Collect();
            Resources.UnloadUnusedAssets();
        }
        catch (Exception ex)
        {

        }
		#if UNITY_EDITOR
		UnityEditor.AssetDatabase.Refresh();
		#endif
    }	
	/// <summary>
    /// 设置截图区域 
    /// </summary>
    /// <param name="_r"></param>
	public static void SetScreenRect (Rect _r)
	{
		screen = _r;
	}
	public static void BeginShotNow (MonoBehaviour monoBehaviour)
	{
	   monoBehaviour.StartCoroutine(MakeImage ());
	}	

	private static IEnumerator MakeImage ()
	{
		//reset screen rect if need full screen
		screen = new Rect(0, 0, Screen.width, Screen.height);
		//if need change screen rect, set in delegate
		if (onShotBeginCallBack != null) onShotBeginCallBack ();
		yield return new WaitForEndOfFrame ();
		screen.width = (int)screen.width;
		screen.height = (int)screen.height;
		Texture2D texture2D = new Texture2D((int)(screen.width), (int)(screen.height), TextureFormat.ARGB32, false);
		texture2D.ReadPixels(screen,0,0, true);
		texture2D.Apply();
		//创建图片
		SaveTexture(texture2D, shotPath);
		// TextureScale.Bilinear (texture2D, 128, (int)(128f / texture2D.width * texture2D.height));
		//创建缩略图
		// SaveTexture(texture2D, thumbPath);
		if(onShotFinishedCallBack!=null){
			onShotFinishedCallBack();
		}		
	}

	/// <summary>
	/// Gets the shot path on ios and android
	/// </summary>
	/// <value>The shot path.</value>
	public static string shotPath 
	{
		get{
			string tempPath;
#if UNITY_EDITOR
			tempPath = Application.dataPath;
#elif UNITY_ANDROID || UNITY_IOS
			tempPath = Application.persistentDataPath;
			#elif PLATFORM_SUPPORTS_MONO
			return "";
#endif
            if (!Directory.Exists(Path.Combine(tempPath, "screenshots")))
            {
                Directory.CreateDirectory(Path.Combine(tempPath, "screenshots"));
            }
			return string.Format("{0}/screenshots/shot.jpg",tempPath);
		}
	}
	public static string thumbPath 
	{
		get{
			string tempPath;
			#if UNITY_EDITOR
			tempPath = Application.dataPath;
			#elif UNITY_ANDROID || UNITY_IOS
			tempPath = Application.persistentDataPath;
			#elif PLATFORM_SUPPORTS_MONO
			return "";
			#endif
			if (!Directory.Exists(Path.Combine(tempPath, "screenshots")))
			{
				Directory.CreateDirectory(Path.Combine(tempPath, "screenshots"));
			}
			Debug.Log("string.Format:"+string.Format("{0}/screenshots/thumb.jpg",tempPath));
			return string.Format("{0}/screenshots/thumb.jpg",tempPath);
		}
	}
		
}

public class TextureScale
{
	public class ThreadData
	{
		public int start;
		public int end;
		public ThreadData (int s, int e) {
			start = s;
			end = e;
		}
	}
	
	private static UnityEngine.Color[] texColors;
	private static UnityEngine.Color[] newColors;
	private static int w;
	private static float ratioX;
	private static float ratioY;
	private static int w2;
	private static int finishCount;
	private static Mutex mutex;
	
	public static void Point (Texture2D tex, int newWidth, int newHeight)
	{
		ThreadedScale (tex, newWidth, newHeight, false);
	}
	
	public static void Bilinear (Texture2D tex, int newWidth, int newHeight)
	{
		ThreadedScale (tex, newWidth, newHeight, true);
	}
	
	private static void ThreadedScale (Texture2D tex, int newWidth, int newHeight, bool useBilinear)
	{
		texColors = tex.GetPixels();
		newColors = new UnityEngine.Color[newWidth * newHeight];
		if (useBilinear)
		{
			ratioX = 1.0f / ((float)newWidth / (tex.width-1));
			ratioY = 1.0f / ((float)newHeight / (tex.height-1));
		}
		else {
			ratioX = ((float)tex.width) / newWidth;
			ratioY = ((float)tex.height) / newHeight;
		}
		w = tex.width;
		w2 = newWidth;
		var cores = Mathf.Min(SystemInfo.processorCount, newHeight);
		var slice = newHeight/cores;
		
		finishCount = 0;
		if (mutex == null) {
			mutex = new Mutex(false);
		}
		if (cores > 1)
		{
			int i = 0;
			ThreadData threadData;
			for (i = 0; i < cores-1; i++) {
				threadData = new ThreadData(slice * i, slice * (i + 1));
				ParameterizedThreadStart ts = useBilinear ? new ParameterizedThreadStart(BilinearScale) : new ParameterizedThreadStart(PointScale);
				Thread thread = new Thread(ts);
				thread.Start(threadData);
			}
			threadData = new ThreadData(slice*i, newHeight);
			if (useBilinear)
			{
				BilinearScale(threadData);
			}
			else
			{
				PointScale(threadData);
			}
			while (finishCount < cores)
			{
				Thread.Sleep(1);
			}
		}
		else
		{
			ThreadData threadData = new ThreadData(0, newHeight);
			if (useBilinear)
			{
				BilinearScale(threadData);
			}
			else
			{
				PointScale(threadData);
			}
		}
		
		tex.Resize(newWidth, newHeight);
		tex.SetPixels(newColors);
		tex.Apply();
	}
	
	public static void BilinearScale (System.Object obj)
	{
		ThreadData threadData = (ThreadData) obj;
		for (var y = threadData.start; y < threadData.end; y++)
		{
			int yFloor = (int)Mathf.Floor(y * ratioY);
			var y1 = yFloor * w;
			var y2 = (yFloor+1) * w;
			var yw = y * w2;
			
			for (var x = 0; x < w2; x++) {
				int xFloor = (int)Mathf.Floor(x * ratioX);
				var xLerp = x * ratioX-xFloor;
				newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor+1], xLerp),
				                                       ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor+1], xLerp),
				                                       y*ratioY-yFloor);
			}
		}
		
		mutex.WaitOne();
		finishCount++;
		mutex.ReleaseMutex();
	}
	
	public static void PointScale (System.Object obj)
	{
		ThreadData threadData = (ThreadData) obj;
		for (var y = threadData.start; y < threadData.end; y++)
		{
			var thisY = (int)(ratioY * y) * w;
			var yw = y * w2;
			for (var x = 0; x < w2; x++) {
				newColors[yw + x] = texColors[(int)(thisY + ratioX*x)];
			}
		}
		
		mutex.WaitOne();
		finishCount++;
		mutex.ReleaseMutex();
	}
	
	private static UnityEngine.Color ColorLerpUnclamped (UnityEngine.Color c1, UnityEngine.Color c2, float value)
	{
		return new UnityEngine.Color (c1.r + (c2.r - c1.r)*value, 
		                  c1.g + (c2.g - c1.g)*value, 
		                  c1.b + (c2.b - c1.b)*value, 
		                  c1.a + (c2.a - c1.a)*value);
	}
}